package top.xia17.plugins.fast.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import top.xia17.plugins.fast.common.database.jpa.extension.JpaTxServiceImpl;
import top.xia17.plugins.fast.common.exceptions.BadRequestException;
import top.xia17.plugins.fast.common.utils.TreeUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import top.xia17.plugins.fast.user.dao.entity.Menu;
import top.xia17.plugins.fast.user.dao.repository.MenuRepository;
import top.xia17.plugins.fast.user.ds.UserDDS;
import top.xia17.plugins.fast.user.model.dto.MenuDto;
import top.xia17.plugins.fast.user.model.enums.MenuType;
import top.xia17.plugins.fast.user.model.mapstruct.MenuMapstruct;
import top.xia17.plugins.fast.user.model.resp.MenuVo;
import top.xia17.plugins.fast.user.service.MenuService;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 菜单serviceImpl
 *
 * @author xia17
 * @date 2022/1/17
 */
@Service
@RequiredArgsConstructor
@UserDDS
public class MenuServiceImpl extends JpaTxServiceImpl<Menu, Long, MenuRepository> implements MenuService {

    private final MenuMapstruct menuMapstruct;

    @Override
    public void createBefore(Menu entity) {
        if (entity.getSort() == null || entity.getSort() < 0) {
            entity.setSort(10);
        }
        entity.setSubCount(0);
        // 选择的上一级需要存在
        this.checkPid(entity);
    }

    public void checkPid(Menu menu) {
        // 父节点是否存在
        if (menu.getPid() == null) {
            menu.setPid(0L);
        }
        if (menu.getPid() < 0) {
            throw new BadRequestException("参数异常，pid小于0");
        }
        if (menu.getPid() > 0) {
            Menu parent = this.findByIdOrThrow(menu.getPid());
            if (parent.getType() == MenuType.BUTTON) {
                throw new BadRequestException("父节点的菜单类型不能为按钮！");
            }
            this.setAttribute("parent", parent);
        }
    }

    @Override
    public void createAfter(Menu entity) {
        // 是否有父节点
        Menu parent = this.getAttributeBean("parent");
        if (parent != null) {
            parent.setSubCount(parent.getSubCount() + 1);
            this.baseRepository.save(parent);
        }
    }

    @Override
    public void updateProperty(Menu entity, Menu resource) {
        entity.setTitle(resource.getTitle())
                .setComponentName(resource.getComponentName())
                .setSort(resource.getSort())
                .setComponent(resource.getComponent())
                .setPath(resource.getPath())
                .setType(resource.getType())
                .setPermission(resource.getPermission())
                .setIcon(resource.getIcon())
                .setCache(resource.getCache())
                .setHidden(resource.getHidden())
                .setPid(resource.getPid())
                .setExternalLink(resource.getExternalLink())
                .setMobile(resource.getMobile());
    }

    @Override
    public void updateBefore(Menu entity, Menu resource) {
        if (resource.getSort() == null || resource.getSort() < 0) {
            resource.setSort(10);
        }
        if (!entity.getPid().equals(resource.getPid())) {
            if (entity.getId().equals(resource.getPid())) {
                throw new BadRequestException("父节点不能是自己");
            }
            this.setAttribute("changePid", true);
            this.setAttribute("oldPid", entity.getPid());
            // 选择的上一级需要存在
            this.checkPid(entity);
        }
    }

    @Override
    public void updateAfter(Menu entity) {
        Boolean changePid = this.getAttributeBean("changePid");
        if (changePid == null || !changePid) {
            return;
        }
        // 说明修改了父节点
        Long oldPid = this.getAttributeBean("oldPid");
        if (oldPid != 0) {
            Menu oldMenu = this.findByIdOrThrow(oldPid);
            oldMenu.setSubCount(oldMenu.getSubCount() - 1);
            this.baseRepository.save(oldMenu);
        }
        Menu parent = this.getAttributeBean("parent");
        if (parent != null) {
            parent.setSubCount(parent.getSubCount() + 1);
            this.baseRepository.save(parent);
        }
    }

    @Override
    public List<MenuVo> getMenuTreeByRoles(Collection<Long> roleIds, Boolean mobile) {
        if (roleIds.size() == 0) {
            return Collections.emptyList();
        }
        List<Menu> menus;
        if (mobile == null) {
            menus = this.baseRepository.myFindMenuTreeByRoles(roleIds);
        } else {
            menus = this.baseRepository.myFindMenuTreeByRoles(roleIds, mobile);
        }
        List<MenuVo> menuVos = menus.stream()
                // 进行去重
                .distinct()
                .map(e -> {
                    MenuVo menuVo = new MenuVo();
                    BeanUtil.copyProperties(e, menuVo, true);
                    return menuVo;
                })
                .collect(Collectors.toList());
        // 获取根节点
        List<MenuVo> roots = menuVos.stream().filter(e -> e.getPid() == 0).collect(Collectors.toList());
        // 构建树结构
        TreeUtil.build(roots,
                rootId -> menuVos.stream().filter(e -> e.getPid().equals(rootId)).collect(Collectors.toList()),
                MenuVo::getId,
                MenuVo::setChildren);
        return roots;
    }

    @Override
    public List<MenuDto> getMenuTree() {
        List<MenuDto> list = menuMapstruct.toDto(this.findAll(null));
        // 获取根节点
        List<MenuDto> roots = list.stream().filter(d -> d.getPid() == 0).collect(Collectors.toList());
        if (roots.isEmpty()) {
            return roots;
        }
        // 构建树
        TreeUtil.build(roots,
                root -> list.stream().filter(d -> d.getPid().equals(root)).collect(Collectors.toList()),
                MenuDto::getId,
                MenuDto::setChildren);
        return roots;
    }
}
